extern crate libc;

use libc::{fork, msgget, msgsnd, msgrcv, msgctl, IPC_PRIVATE, IPC_EXCL, IPC_RMID};
use std::{mem, ptr, io};
use std::io::Write; // for flush stdout

const MY_TYPE: i64 = 9527;

#[repr(C)]
struct MsgBuf {
    mtype: libc::c_long,
    mtext: [u8; 100],
    number: i32,
}

fn main() {
    let msgid = unsafe { msgget(IPC_PRIVATE, 0666 | IPC_EXCL) };

    if msgid == -1 {
        eprintln!("msgget failed");
        return;
    }

    match unsafe { fork() } {
        -1 => eprintln!("fork failed"),
        0 => {
            println!("Child process is waiting for msg:");
            let mut buf: MsgBuf = unsafe { mem::zeroed() };
            unsafe {
                msgrcv(msgid, &mut buf as *mut _ as *mut _, 
                      mem::size_of_val(&buf.mtext) + mem::size_of_val(&buf.number),
                      MY_TYPE, 0);
            }
            let received_str = String::from_utf8_lossy(&buf.mtext);
            println!("Child process read from msg: {}, {}", received_str, buf.number);
            // Remove the message queue after reading
            unsafe { msgctl(msgid, IPC_RMID, ptr::null_mut()) };
        },
        pid => {
            std::thread::sleep(std::time::Duration::from_secs(1));

            let mut buf: MsgBuf = unsafe { mem::zeroed() };
            buf.mtype = MY_TYPE;
            print!("Please enter a string you want to send:\n");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut String::from_utf8_lossy(&mut buf.mtext).into_owned()).unwrap();
            println!("Please enter a number you want to send:");
            io::stdout().flush().unwrap();
            let mut num_str = String::new();
            io::stdin().read_line(&mut num_str).unwrap();
            buf.number = num_str.trim().parse().unwrap();

            unsafe { msgsnd(msgid, &buf as *const _ as *const _, 
                            mem::size_of_val(&buf.mtext) + mem::size_of_val(&buf.number), 0) };

            // Wait for the child process to finish
            unsafe { libc::waitpid(pid, ptr::null_mut(), 0) };
        }
    }
}
